package com.hnzq.cloud.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hnzq.cloud.commons.JWTHelper;
import com.hnzq.cloud.model.Result;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;

/**
 * @ClassName 类名： AuthFilter
 * @Description 描述：
 * @Author 倪西
 * @Date 时间：2022/1/14 15:50
 **/
@Component
public class AuthFilter implements GlobalFilter, Ordered {

    @Resource
    private ObjectMapper objectMapper;

    @Resource
    private JWTHelper jwtHelper;

    @Resource
    private RedissonClient redisson;

    @Value("${auth.uri}")
    private String[] excludeAuthPages;

    //用于URLs字符串匹配
//    private AntPathMatcher apm = new AntPathMatcher();

//    public AuthFilter(JWTHelper jwtHelper, ObjectMapper objectMapper, String[] excludeAuthPages) {
//        this.jwtHelper = jwtHelper;
//        this.objectMapper = objectMapper;
//        this.excludeAuthPages = excludeAuthPages;
//    }

    private Mono<Void> getVoidMono(ServerHttpResponse response,String message,Integer code){
        Result result = Result.newInstance().setCode(code).setMessage(message);

        //解决中文乱码问题
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");

        //转换成json
        String jsonResult = null;
        try {
            jsonResult = objectMapper.writeValueAsString(result);
        } catch (JsonProcessingException e) {
            jsonResult="error";
        }

        DataBuffer dataBuffer = null;
        try {
            dataBuffer = response.bufferFactory().wrap(jsonResult.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return response.writeWith(Mono.just(dataBuffer));

    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        String path = request.getPath().value();
        System.out.println(path);
        //过滤请求白名单
        for (String uri : excludeAuthPages) {
            if (uri.equals(path)){
                return chain.filter(exchange);
            }
        }

        String token = request.getHeaders().getFirst("token");
        if (token==null||token.length()==0||token.trim().length()==0){
            return getVoidMono(response,"未登录",403);
        }
        Claims claims=null;
        try {
            claims = jwtHelper.parseJWT(token);
        }catch (JwtException e){
            e.printStackTrace();
        }catch (Exception e){
            e.printStackTrace();
        }
        Object key =claims.get("login:user");
        RBucket<Object> bucket = redisson.getBucket(key.toString());
        if (!bucket.isExists()){
            return getVoidMono(response,"登录信息已过期，请重新登录",402);
        }
        HashMap<String, Object> map = (HashMap<String, Object>) bucket.get();
        Object oldToken = map.get("token");
        if (!token.equals(oldToken.toString())){
            return getVoidMono(response,"登录信息已失效，请重新登录",402);
        }



        Object userId = map.get("userId");
        request.mutate().header("userId",userId.toString());
        Object roleId = map.get("roleId");
        RBucket<Object> resourceRedis = redisson.getBucket("roleId:" + roleId.toString());
        List<String> resources = (List<String>) resourceRedis.get();
        System.out.println(resources);
        for (String resource : resources){
            if (resource.equals(path)){
                return chain.filter(exchange);
            }
        }
        return getVoidMono(response,"无访问权限",401);
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE-10;
    }
}
